<template>
  <el-card style="margin-bottom: 10px;">
    <el-form :inline="true" class="demo-form-inline" style="margin-top: 10px;">
      <el-form-item label="货品类型">
        <el-input v-model="pageinfo.keyword" placeholder="请输入货品类型编号/名称" clearable />
      </el-form-item>
      <el-form-item label="状态">
        <el-select v-model="pageinfo.state" placeholder="请选择" clearable>
          <el-option label="启用" :value="1" />
          <el-option label="停用" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="success" @click="getList">查询</el-button>
        <el-button type="info" @click="reset">重置</el-button>

      </el-form-item>
    </el-form>
  </el-card>

  <el-card style="margin-bottom: 10px;">
    <el-button type="primary" @click="openDrawer">新增</el-button>
    <el-button type="warning" style="margin-left:8px;" @click="exportExcel">导出</el-button>
    <el-table :data="treeData" style="width: 100%; margin-top: 10px;" height="520px" row-key="producttypeId"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" default-expand-all>
      <el-table-column type="index" label="序号" width="55" fixed="left" />
      <el-table-column prop="producttypeCode" label="货品类型编号" />
      <el-table-column prop="producttypeName" label="货品类型名称" />
      <el-table-column prop="producttypeOrderby" label="排序" />
      <el-table-column label="状态">
        <template #default="scope">
          <span v-if="scope.row.producttypeState == 1">启用</span>
          <span v-else-if="scope.row.producttypeState == 2">停用</span>
          <span v-else>-</span>
        </template>
      </el-table-column>
      <el-table-column prop="producttypeDesc" label="备注" />
      <el-table-column label="操作" fixed="right" width="160">
        <template #default="scope">
          <el-button type="primary" link @click="openEdit(scope.row)">编辑</el-button>
          <el-button type="danger" link @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-card>

  <!-- 新建货品类型 抽屉 -->
  <el-drawer v-model="drawer.visible" :title="isEdit ? '修改' : '新增'" direction="rtl" size="38%">
    <el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
        <el-form-item label="上级分类" prop="producttypeParentid">
          <el-tree-select
            v-model="form.producttypeParentid"
            placeholder="请选择上级分类"
            style="width: 100%;"
            check-strictly
            clearable
            :data="productTypeTreeOptions"
            :props="{ label: 'producttypeName', value: 'producttypeId', children: 'children' }"
            node-key="producttypeId"
          />
      </el-form-item>
      <el-form-item label="货品类型编号">
        <el-input v-model="form.producttypeCode" placeholder="自动获取系统编号" class="readonly-input" readonly>
          <template #append>
            <el-button @click="generateProductTypeCode" :loading="generatingProductTypeCode">
              自动生成
            </el-button>
          </template>
        </el-input>
      </el-form-item>
      <el-form-item label="货品类型名称" prop="producttypeName" required>
        <el-input v-model="form.producttypeName" placeholder="请输入" />
      </el-form-item>
      <el-form-item label="排序">
        <el-input v-model.number="form.producttypeOrderby" placeholder="请输入" />
      </el-form-item>
      <el-form-item label="状态" prop="producttypeState" required>
        <el-radio-group v-model="form.producttypeState">
          <el-radio :value="1">启用</el-radio>
          <el-radio :value="2">停用</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="备注">
        <el-input v-model="form.producttypeDesc" type="textarea" placeholder="请输入" />
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="drawer.visible = false">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
    </template>
  </el-drawer>
</template>

<script lang="ts" setup>
import { onMounted, reactive, ref, watch, toRaw } from 'vue'
import myaxios from '@/http/MyAxios'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'

const pageinfo = reactive({
  keyword: '',
  state: null as null | number,
})

const treeData = ref([] as any[])
const generatingProductTypeCode = ref(false)

const TIME_SEGMENT_ORDER = ['YYYY', 'YY', 'MM', 'DD', 'HH', 'MI', 'SS']
const pad = (n: number, len = 2) => `${n}`.padStart(len, '0')

const buildCodeFromRule = (rule: any) => {
  const now = new Date()
  const segments = (rule?.timeRule || '')
    .split(',')
    .map((s: string) => s.trim().toUpperCase())
    .filter(Boolean)
    .sort((a: string, b: string) => {
      const idxA = TIME_SEGMENT_ORDER.indexOf(a)
      const idxB = TIME_SEGMENT_ORDER.indexOf(b)
      if (idxA === -1 && idxB === -1) return 0
      if (idxA === -1) return 1
      if (idxB === -1) return -1
      return idxA - idxB
    })

  const timePart = segments
    .map((seg: string) => {
      switch (seg) {
        case 'YYYY': return String(now.getFullYear())
        case 'YY': return String(now.getFullYear()).slice(-2)
        case 'MM': return pad(now.getMonth() + 1)
        case 'DD': return pad(now.getDate())
        case 'HH': return pad(now.getHours())
        case 'MI': return pad(now.getMinutes())
        case 'SS': return pad(now.getSeconds())
        default: return ''
      }
    })
    .join('')

  const serialLength = Number(rule?.serialLength ?? 3)
  const serial = '1'.padStart(serialLength > 0 ? serialLength : 3, '0')
  return `${rule?.codePrefix || ''}${timePart}${serial}`
}

const requestNumber = async (targetCode: string, targetName: string) => {
  try {
    const res = await myaxios.get('/api/Number/GenerateNumber', {
      params: { targetCode, targetName }
    })
    if (res?.data?.code === 200 && res?.data?.data) {
      return String(res.data.data)
    }
    throw new Error(res?.data?.message || '生成编号失败')
  } catch (err) {
    console.warn(`[numbering] GenerateNumber 接口不可用 (${targetCode})，尝试规则生成`, err)
    const ruleRes = await myaxios.get('/api/Number/QueryNumberingRules', {
      params: { targetCode, targetName }
    })
    const list = Array.isArray(ruleRes?.data?.data) ? ruleRes.data.data : []
    if (list.length > 0) {
      return buildCodeFromRule(list[0])
    }
    throw new Error('未找到对应的编号规则，请先配置编号规则')
  }
}

const generateProductTypeCode = async () => {
  if (generatingProductTypeCode.value) return
  generatingProductTypeCode.value = true
  try {
    form.producttypeCode = await requestNumber('ProductType', '货品类型')
    ElMessage.success('编号生成成功')
  } catch (error: any) {
    ElMessage.error(error?.message || '生成编号失败')
  } finally {
    generatingProductTypeCode.value = false
  }
}

// 统一设置树节点的 hasChildren 属性
const setHasChildren = (nodes: any[]) => {
  nodes.forEach(node => {
    node.hasChildren = Array.isArray(node.children) && node.children.length > 0
    if (node.children && node.children.length > 0) {
      setHasChildren(node.children)
    }
  })
}

// 构建树形结构（兼容扁平数据时使用）
const buildTree = (items: any[], idKey: string, parentIdKey: string) => {
  const tree: any[] = []
  const map: { [key: string]: any } = {}

  // 创建映射
  items.forEach(item => {
    map[item[idKey]] = { ...item, children: [] }
  })

  // 构建树
  items.forEach(item => {
    const parentId = item[parentIdKey]
    if (parentId && map[parentId]) {
      map[parentId].children.push(map[item[idKey]])
    } else {
      tree.push(map[item[idKey]])
    }
  })

  setHasChildren(tree)
  console.log(tree);
  return tree
  
}

// 过滤树形数据
const filterTree = (nodes: any[]): any[] => {
  const keyword = pageinfo.keyword?.toLowerCase() || ''
  const state = pageinfo.state

  const filterNode = (node: any): any | null => {
    // 检查当前节点是否匹配
    const matchKeyword = !keyword ||
      (node.producttypeCode?.toLowerCase().includes(keyword) ||
        node.producttypeName?.toLowerCase().includes(keyword))
    const matchState = state === null || node.producttypeState === state

    // 递归过滤子节点
    const filteredChildren = (node.children || [])
      .map((child: any) => filterNode(child))
      .filter((child: any) => child !== null)

    // 如果当前节点匹配，或者有匹配的子节点，则保留
    if ((matchKeyword && matchState) || filteredChildren.length > 0) {
      const result = {
        ...node,
        children: filteredChildren,
        hasChildren: filteredChildren.length > 0
      }
      return result
    }

    return null
  }

  return nodes.map(filterNode).filter((node: any) => node !== null)
}

const getList = () => {
  // 直接调用后端树形接口
  myaxios({
    url: '/api/Product/GetProductTypeTree',
    method: 'get',
  })
    .then((res) => {
      const tree = res.data.data || []
      // 补充 hasChildren 字段
      setHasChildren(tree)
      // 应用过滤
      treeData.value = filterTree(tree)
    })
    .catch((err) => {
      console.log(err)
      ElMessage.error('获取数据失败')
    })
}

const reset = () => {
  pageinfo.keyword = ''
  pageinfo.state = null
}

// 抽屉与表单
const drawer = reactive({ visible: false })
const isEdit = ref(false)
const formRef = ref<FormInstance>()
const form = reactive({
  producttypeId: null as null | number,
  producttypeParentid: null as null | number,
  producttypeCode: '',
  producttypeName: '',
  producttypeOrderby: undefined as any,
  producttypeState: 1,
  producttypeDesc: ''
})

const rules = reactive({
  producttypeName: [{ required: true, message: '请输入货品类型名称', trigger: 'blur' }],
  producttypeState: [{ required: true, message: '请选择状态', trigger: 'change' }],
})

const productTypeTreeOptions = ref<any[]>([])

const cloneTree = (nodes: any[]): any[] =>
  nodes.map(node => ({
    ...node,
    children: node.children ? cloneTree(node.children) : [],
  }))

const filterTreeNodes = (nodes: any[], excludeId: number | null): any[] => {
  return nodes
    .map(node => {
      if (excludeId !== null && node.producttypeId === excludeId) {
        return null
      }
      const children = node.children ? filterTreeNodes(node.children, excludeId) : []
      return { ...node, children }
    })
    .filter(Boolean) as any[]
}

const loadProductTypeOptions = (excludeId: number | null = null) => {
  // 使用后端树形接口获取数据，构建用于上级分类下拉的树
  myaxios({ url: '/api/Product/GetProductTypeTree', method: 'get' })
    .then(res => {
      const allData = res.data.data || []
      const tree = buildTree(allData, 'producttypeId', 'producttypeParentid')
      const cloned = cloneTree(tree)
      productTypeTreeOptions.value = filterTreeNodes(cloned, excludeId)
    })
}

const handleParentChange = (value: number | null) => {
  form.producttypeParentid = value ?? null
}

const resetForm = () => {
  form.producttypeId = null
  form.producttypeParentid = null
  form.producttypeCode = ''
  form.producttypeName = ''
  form.producttypeOrderby = undefined as any
  form.producttypeState = 1
  form.producttypeDesc = ''
}

const openDrawer = () => {
  isEdit.value = false
  resetForm()
  loadProductTypeOptions(null)
  drawer.visible = true
}

const openEdit = (row: any) => {
  isEdit.value = true
  // 编辑时排除当前项及其子项，避免循环引用
  loadProductTypeOptions(row.producttypeId)
  // 回填
  form.producttypeId = row.producttypeId
  form.producttypeParentid = row.producttypeParentid ?? null
  form.producttypeCode = row.producttypeCode || ''
  form.producttypeName = row.producttypeName || ''
  form.producttypeOrderby = row.producttypeOrderby
  form.producttypeState = row.producttypeState
  form.producttypeDesc = row.producttypeDesc || ''
  drawer.visible = true
}

const save = async () => {
  const formInstance = formRef.value
  if (!formInstance) return
  try {
    await formInstance.validate()
  } catch {
    return
  }

  if (!form.producttypeCode) {
    await generateProductTypeCode()
    if (!form.producttypeCode) {
      ElMessage.warning('请先生成货品类型编号')
      return
    }
  }

  const payload = {
    ...toRaw(form),
    producttypeId: form.producttypeId ?? 0,
    producttypeOrderby: Number(form.producttypeOrderby) || 0,
    producttypeState: Number(form.producttypeState) || 1,
    producttypeParentid: form.producttypeParentid ?? null
  }

  myaxios({
    url: isEdit.value ? '/api/Product/UpdateProductType' : '/api/Product/CreateProductType',
    method: 'post',
    data: payload
  })
    .then(res => {
      if (res.data.code === 200) {
        ElMessage.success(res.data.message || '创建成功')
        drawer.visible = false
        // 重置表单
        resetForm()
        getList()
      } else {
        ElMessage.error(res.data.message || (isEdit.value ? '修改失败' : '创建失败'))
      }
    })
    .catch(() => {
      ElMessage.error(isEdit.value ? '修改失败' : '创建失败')
    })
}

const handleDelete = (row: any) => {
  ElMessageBox.confirm('确定要删除该货品类型吗？', '提示', { type: 'warning' })
    .then(() => {
      return myaxios({
        url: '/api/Product/DeleteProductType',
        method: 'delete',
        params: { producttypeId: row.producttypeId }
      })
    })
    .then(res => {
      if (!res) return
      if (res.data.code === 200) {
        ElMessage.success(res.data.message || '删除成功')
        getList()
      } else {
        ElMessage.error(res.data.message || '删除失败')
      }
    })
    .catch(() => { })
}

const exportExcel = () => {
  myaxios({
    url: '/api/Product/ExportProductType',
    method: 'get',
    params: { keyword: pageinfo.keyword, state: pageinfo.state },
    responseType: 'blob'
  })
    .then((res) => {
      const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
      // 从响应头获取文件名
      const disposition = (res as any).headers?.['content-disposition'] || (res as any).headers?.get?.('content-disposition')
      let filename = '货品类型.xlsx'
      if (disposition && disposition.includes('filename')) {
        const match = /filename\*=UTF-8''([^;]+)|filename=([^;]+)/i.exec(disposition)
        filename = decodeURIComponent((match?.[1] || match?.[2] || filename).replace(/\"/g, '').trim())
      }
      const link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.download = filename
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      URL.revokeObjectURL(link.href)
      ElMessage.success('导出成功')
    })
    .catch(() => {
      ElMessage.error('导出失败')
    })
}

onMounted(() => {
  getList()
})

// 监听搜索条件变化，重新过滤
watch([() => pageinfo.keyword, () => pageinfo.state], () => {
  getList()
})
</script>

<style>
.demo-form-inline .el-input {
  --el-input-width: 220px;
}

.demo-form-inline .el-select {
  --el-select-width: 220px;
}

:deep(.readonly-input .el-input__wrapper) {
  background-color: #f5f7fa;
}
</style>
